package com.my.chapter21;

import java.io.IOException;
import java.io.PipedReader;
import java.io.PipedWriter;
import java.util.ArrayList;
import java.util.Random;
import java.util.concurrent.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Test {
    public static void main(String[] args) throws Exception {
        Sender2 sender = new Sender2();
        Receiver2 receiver = new Receiver2(sender);
        ExecutorService exec = Executors.newCachedThreadPool();
        exec.execute(sender);
        exec.execute(receiver);
        TimeUnit.SECONDS.sleep(4);
        exec.shutdownNow();
    }
}

class TaskWithResult implements Callable<String>{
    private int id;
    public TaskWithResult(int id){
        this.id = id;
    }

    @Override
    public String call() throws Exception {
        return "id = " + id;
    }
}

class LiftOff implements Runnable{
    protected int countDown = 5;
    private static int taskCount = 0;
    private static  int id = taskCount++;
    public LiftOff(){}
    public LiftOff(int countDown){ this.countDown = countDown; }
    public String status(){
        return "#" + id + "(" +
                (countDown>0 ? countDown : "LiftOff!") + ").";
    }
    @Override
    public void run() {
        while (countDown-- >0){
            System.out.println(status());
            Thread.yield();
        }
    }
}

class SleepingTask extends LiftOff{
    public void run(){
        try {
            while ((countDown-- > 0)){
                System.out.print(status());
                TimeUnit.MILLISECONDS.sleep(100);
            }
        }catch (InterruptedException e){
            System.out.println(e);
        }
    }
}

class SimplePriorities implements Runnable{
    private int countDown = 3;
    private volatile double d;
    private int priority;
    public SimplePriorities(int priority){
        this.priority = priority;
    }

    @Override
    public String toString() {
        return Thread.currentThread().getName() + "：" + countDown;
    }

    public void run(){
        Thread.currentThread().setPriority(priority);
        while (true){
            for(int i=0;i<100000;i++){
                d+=(Math.PI + Math.E) / (double) i;
                if(i%1000 == 0)
                    Thread.yield();
            }
            System.out.println(this + "；" + Thread.currentThread().getPriority());
            if(--countDown == 0) return;
        }
    }

    public static void main(String[] args) {
        ExecutorService exec = Executors.newCachedThreadPool();
        for(int i=0;i<3;i++)
            exec.execute(new SimplePriorities(Thread.MIN_PRIORITY));
        exec.execute(new SimplePriorities(Thread.MAX_PRIORITY));
    }
}

class DaemonThreadFactory implements ThreadFactory{
    public Thread newThread(Runnable r){
        Thread t = new Thread(r);
        t.setDaemon(true);//设置为后台线程
        return t;
    }
}

class DaemonThreadPoolExecutor extends ThreadPoolExecutor{
    public DaemonThreadPoolExecutor(){
        super(0,Integer.MAX_VALUE,60L,TimeUnit.SECONDS,
                new SynchronousQueue<Runnable>(),
                new DaemonThreadFactory());
        /*
        * corePoolSize:指定了线程池中的线程数量
        * maximumPoolSize:指定了线程池中的最大线程数量
        * keepAliveTime:当线程池中空闲线程数量超过corePoolSize时，多余的线程会在多长时间内被销毁
        * unit:keepAliveTime的单位
        * workQueue:任务队列，被添加到线程池中，但尚未被执行的任务
        * threadFactory:线程工厂，用于创建线程，一般用默认即可*/
    }
}

class DaemonFromFactory implements Runnable{
    public void run(){
        try{
            while(true){
                TimeUnit.MILLISECONDS.sleep(100);
                System.out.println(Thread.currentThread() + " " + this);
            }
        }catch (InterruptedException e){
            System.out.println(e);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ExecutorService exec = new DaemonThreadPoolExecutor();
        for(int i=0;i<10;i++)
            exec.execute(new DaemonFromFactory());
        System.out.println("All daemons started");
        TimeUnit.MILLISECONDS.sleep(500);
    }
}

class ExceptionThread implements Runnable{
    public void run(){
        Thread t = Thread.currentThread();
        System.out.println("run by " + t);
        System.out.println("eh = " + t.getUncaughtExceptionHandler());
        throw new RuntimeException();
    }
}

class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler{
    @Override
    public void uncaughtException(Thread t, Throwable e) {
        System.out.println("caught " + e);
    }
}

class HandlerThreadFactory implements ThreadFactory{
    @Override
    public Thread newThread(Runnable r) {
        Thread t = new Thread(r);
        System.out.println("created " + t);
        t.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
        System.out.println("eh = " + t.getUncaughtExceptionHandler());
        return t;
    }
}

class CaptureUncaughtException{
    public static void main(String[] args) {
        ExecutorService exec = Executors.newCachedThreadPool(new HandlerThreadFactory());
        exec.execute(new ExceptionThread());
    }
}

class SynchronizedEventGenerator{
    private int currentEventValue = 0;
    public synchronized int next(){
        ++currentEventValue;
        Thread.yield();
        ++currentEventValue;
        return currentEventValue;
    }
}

class MutexEventGenerator{
    private int currentEventValue = 0;
    private Lock lock = new ReentrantLock();
    public int next(){
        lock.lock();
        try {
            ++currentEventValue;
            Thread.yield();
            ++currentEventValue;
            return currentEventValue;
        }finally {
            lock.unlock();
        }
    }
}

class DualSynch{
    private Object syncObject = new Object();
    public synchronized void f(){
        for(int i=0;i<5;i++){
            System.out.println("f()");
            Thread.yield();
        }
    }
    public void g(){
        synchronized (syncObject){
            for(int i=0;i<5;i++){
                System.out.println("g()");
                Thread.yield();
            }
        }
    }
}

class SyncObject{
    public static void main(String[] args) {
        final DualSynch ds = new DualSynch();
        new Thread(){
            public void run(){
                ds.f();
            }
        }.start();
        ds.g();
    }
}

class Sender2 implements Runnable {
    private Random rand = new Random(47);
    private PipedWriter out= new PipedWriter();
    public PipedWriter getPipedWriter() { return out; }
    public void run() {
        try {
            while(true)
                for(char c = 'A'; c <= 'z'; c++) {
                    out.write(c);
                    TimeUnit.MILLISECONDS.sleep(rand.nextInt(500));
                }
        } catch(InterruptedException e) {
            System.out.println(e + " Sender interrupted");
        }catch (IOException e){
            System.out.println(e + " Sender write exception");
        }
    }
}

class Receiver2 implements Runnable {
    private PipedReader in;
    public Receiver2(Sender2 sender) throws IOException { in = new PipedReader(sender.getPipedWriter()); }
    public void run() {
        try {
            while(true) {
                // Blocks until characters are there:
                System.out.print("Read: " + (char)in.read() + ", ");
            }
        }catch (IOException e){
            System.out.println(e + " Receiver read exception");
        }
    }
}


/*Output：
Read: A, Read: B, Read: C, Read: D, Read: E, Read: F, Read: G, Read: H,
java.lang.InterruptedException: sleep interrupted Sender interrupted
java.io.InterruptedIOException Receiver read exception
*/

